#include "bsp.h"
#include "bsp_i2s.h"
#include "ff.h"
#include "stdlib.h"
#include "bsp_wm8978.h"
#include "audio_play.h"

//********************************************************************************
//V1.0 说明
//1,支持16位/24位WAV文件播放
//2,最高可以支持到192K/24bit的WAV格式.
//////////////////////////////////////////////////////////////////////////////////

__wavctrl wavctrl;		 //WAV控制结构体
uuv8 wavtransferend = 0; //sai传输完成标志
uuv8 wavwitchbuf = 0;	 //saibufx指示标志

int16_t i2s_fil_dat_get(void *buff, int16_t len_req);

/*****************************************************************************
* @brief   wav_decode_init.
* @param   path : 文件路径+文件名
* @param   wavx : wav 信息存放结构体指针
* @return  0,成功;1,打开文件失败;2,非WAV文件;3,DATA区域未找到.
*****************************************************************************/
uu8 wav_decode_init(uu8 *path, __wavctrl *wavx)
{
	FIL *ftemp;
	uu8 *buf;
	UINT br = 0;
	uu8 res = 0;

	ChunkRIFF *riff;
	ChunkFMT *fmt;
	ChunkFACT *fact;
	ChunkDATA *data;
	ftemp = (FIL *)malloc( sizeof(FIL));
	buf = malloc( 512);

	if (ftemp && buf) //内存申请成功
	{
		res = f_open(ftemp, (TCHAR *)path, FA_READ); //打开文件
		if (res == FR_OK)
		{
			f_read(ftemp, buf, 512, &br);	//读取512字节在数据
			riff = (ChunkRIFF *)buf;		//获取RIFF块
			if (riff->Format == 0X45564157) //是WAV文件
			{
				fmt = (ChunkFMT *)(buf + 12);						 //获取FMT块
				fact = (ChunkFACT *)(buf + 12 + 8 + fmt->ChunkSize); //读取FACT块
				if (fact->ChunkID == 0X74636166 || fact->ChunkID == 0X5453494C)
					wavx->datastart = 12 + 8 + fmt->ChunkSize + 8 + fact->ChunkSize; //具有fact/LIST块的时候(未测试)
				else
					wavx->datastart = 12 + 8 + fmt->ChunkSize;
				data = (ChunkDATA *)(buf + wavx->datastart); //读取DATA块
				if (data->ChunkID == 0X61746164)			 //解析成功!
				{
					wavx->audioformat = fmt->AudioFormat; //音频格式
					wavx->nchannels = fmt->NumOfChannels; //通道数
					wavx->samplerate = fmt->SampleRate;	  //采样率
					wavx->bitrate = fmt->ByteRate * 8;	  //得到位速
					wavx->blockalign = fmt->BlockAlign;	  //块对齐
					wavx->bps = fmt->BitsPerSample;		  //位数,16/24/32位

					wavx->datasize = data->ChunkSize;	   //数据块大小
					wavx->datastart = wavx->datastart + 8; //数据流开始的地方.

					dbg_print("wavx->audioformat:%d\n", wavx->audioformat);
					dbg_print("wavx->nchannels:%d\n", wavx->nchannels);
					dbg_print("wavx->samplerate:%d\n", wavx->samplerate);
					dbg_print("wavx->bitrate:%d\n", wavx->bitrate);
					dbg_print("wavx->blockalign:%d\n", wavx->blockalign);
					dbg_print("wavx->bps:%d\n", wavx->bps);
					dbg_print("wavx->datasize:%d\n", wavx->datasize);
					dbg_print("wavx->datastart:%d\n", wavx->datastart);
				}
				else
				{
					res = 3; //data区域未找到.
				}
			}
			else
			{
				res = 2; //非wav文件
			}
		}
		else
		{
			res = 1; //打开文件错误
		}
	}
	f_close(ftemp);
	free( ftemp); //释放内存
	free( buf);
	return 0;
}

/*****************************************************************************
* @brief   wav_get_curtime.
* @param   fx : file handle
* @param   wavx : wav 信息存放结构体指针
*****************************************************************************/
void wav_get_curtime(FIL *fx, __wavctrl *wavx)
{
	long long fpos;
	wavx->totsec = wavx->datasize / (wavx->bitrate / 8); //歌曲总长度(单位:秒)
	fpos = fx->fptr - wavx->datastart;					 //得到当前文件播放到的地方
	wavx->cursec = fpos * wavx->totsec / wavx->datasize; //当前播放到第多少秒了?
}

/*****************************************************************************
* @brief   wav_play_song.
* @param   fname : 文件路径+文件名
* @return  .
*****************************************************************************/
uu8 wav_play_song(uu8 *fname)
{
	uu8 key;
	uu8 t = 0;
	uu8 res;
	uu32 fillnum;
	audiodev.file = (FIL *)malloc( sizeof(FIL));
	audiodev.tbuf = malloc( WAV_SAI_TX_DMA_BUFSIZE);

	if (1)
	{
		res = wav_decode_init(fname, &wavctrl); //得到文件的信息

		if (res == 0)							//解析文件成功
		{
			if (wavctrl.bps == 16)
			{
				WM8978_I2S_Cfg(2, 0); 			//飞利浦标准,16位数据长度
				
				bsp_i2s_init(wavctrl.samplerate, I2S_DATABIT_16);
			}
			else if (wavctrl.bps == 24)
			{
				WM8978_I2S_Cfg(2, 2); 			//飞利浦标准,24位数据长度

				bsp_i2s_init(wavctrl.samplerate, I2S_DATABIT_24);
			}

			audio_stop();

			res = f_open(audiodev.file, (TCHAR *)fname, FA_READ); //打开文件
			if (res == 0)
			{
				f_lseek(audiodev.file, wavctrl.datastart); //跳过文件头

				audio_start();

				bsp_i2s_play(i2s_fil_dat_get);

				audio_stop();
			}
			else
			{
				res = 0XFF;
			}
		}
		else
		{
			res = 0XFF;
		}
	}
	else
	{
		res = 0XFF;
	}

	free( audiodev.tbuf);	  //释放内存
	free( audiodev.file);	  //释放内存
	return res;
}

/*****************************************************************************
* @brief   i2s_fil_dat_get.
* @param   buff len
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
int16_t i2s_fil_dat_get(void *buff, int16_t len_req)
{
	UINT len_back;
	
	if (wavctrl.bps == 24)
	{
		word_tt dat32;
		uint32_t *des = buff;
		uint8_t *src = audiodev.tbuf;
		
		// 留一字空白
		len_req -= 4;
		
		f_read(audiodev.file, audiodev.tbuf, (len_req>>2) * 3, &len_back);
		
		dat32.uval = 0;
		
		// 转换数据对齐到4B
		for(int index = 0; index < len_back; index+=3)
		{
			for(int offset = 0; offset <= 2; offset++)
			{
				dat32.v[offset] = *src++;
			}
			
			*des ++ = dat32.uval;
		}
		
		// 总长度
		len_back /= 3;
		len_back *= 4;
	}
	else
	{
		f_read(audiodev.file, buff, len_req, &len_back);
	}
	
	return len_back;
}

